import random
import numpy as np

"""
注意先defender()后beInfected()
"""


class Person:
    """
    _status  int  健康状态 (0: 未感染, 1: 潜伏, 2: 无症状, 3:病发, 4:死亡)  0 green 2 yellow 3 red 4 gray 1 待定
    _infect_time  int  以天数计感染时间 当前感染时有效 感染重置
    _virus  float  病毒感染率 无病毒为0
    _resist_ability  float  抵抗力水平
    _antibody_level  float  抗体水平
    _protect_level  float  防护水平
    _patience  float  耐心值
    _position  int  当前位置 场所_id
    _dorm  int  宿舍_id
    _isolate_time  int  隔离倒计时 隔离7天 非隔离0
    """

    def __init__(self, dorm):
        # 健康状态
        self._status = 0  # (0: 未感染, 1: 潜伏, 2: 无症状, 3:病发, 4:死亡)
        # 感染时间 当前感染时有效 感染重置
        self._infect_time = 0
        # 病毒感染率 无病毒为0
        self._virus = 0
        # 抵抗力水平
        self._resist_ability = np.random.choice([0, 0.05, 0.1], 1, p=[0.2, 0.6, 0.2])[0]
        # 抗体水平
        self._antibody_level = 0
        # 防护水平
        self._protect_level = 0
        # 上次打疫苗间隔
        self._vaccine_interval = 1  # 假设都没打过初值无所谓
        # 耐心值
        self._patience = 0
        # 位置
        self._position = dorm
        # 宿舍
        self._dorm = dorm
        # 是否需要隔离
        self._isolate = 0

    def getStatus(self):
        return self._status

    def getInfectTime(self):
        return self._infect_time

    def getPosition(self):
        return self._position

    def getDorm(self):
        return self._dorm

    def getVirus(self):
        return self._virus

    def getPatience(self):
        return self._patience

    def getProtect(self):
        return self._protect_level

    def getVaccineInterval(self):
        return self._vaccine_interval

    def getIsolate(self):
        return self._isolate

    def setIsolate(self, days=7):
        self._isolate = days

    def setPatience(self, rate):
        self._patience = min(1.0, max(0.0, rate))

    def setProtect(self, rate):
        self._protect_level = min(1.0, max(0.0, rate))

    # 设置位置
    def moveToArea(self, area):
        before = self._position
        self._position = area
        return before

    # 设置病人初始为无症状 已感染2天 virus病毒传染率
    def bePatient0(self, virus):
        self._status = 2
        self._infect_time = 3
        self._virus = virus

    # 被传染   virus病毒传染率
    def beInfected(self, virus):
        if random.random() > self._protect_level:
            self._status = 1
            self._infect_time = 0
            self._virus = virus
            return True
        return False

    # 打疫苗   rate疫苗有效率
    def vaccinate(self, rate):
        self._antibody_level = max(0.0, min(1.0, random.uniform(rate - 0.1, rate + 0.1)))
        self._vaccine_interval = 0

    # 自身免疫
    def defender(self, cure_rate, dead_rate):
        self._vaccine_interval += 1

        if self._status == 0:
            self._antibody_level = 0.998 * self._antibody_level
            if self._isolate > 0:
                self._isolate -= 1

        # 潜伏或无症状
        elif self._status == 1 or self._status == 2:
            """潜伏时根据时间 若无传染性 随机产生传染性 随机变成病发"""
            self._infect_time += 1
            # 感染时间小于3天则不变化
            if self._infect_time < 3:
                return self._status
            elif self._infect_time >= 14:
                self._status = 3
                return self._status
            if random.random() * 10 - 6 > self._antibody_level:
                if random.random() < max(self._resist_ability, self._antibody_level):  # 自愈
                    self._status = 0
                    self._virus = 0
                    self._antibody_level = random.uniform(0.95, 1.0)  # 抗体水平设置
                elif random.random() < 0.1:
                    self._status = 2
                else:  # 病发
                    self._status = 3

        # 确诊
        elif self._status == 3:
            """病发期根据时间 根据是否在医院提高治愈概率并降低死亡概率 病毒有可能变异可能提高感染率可能降低感染力 死亡率同时和感染率成反比"""
            self._infect_time += 1
            self._isolate = 7
            # 治愈速率
            cure_rate = cure_rate / 4 + (self._resist_ability + self._antibody_level) / 32
            # 死亡率
            dead_rate = min(1., max(0., dead_rate * (1. - self._antibody_level) + 0.001 - self._resist_ability / 100))
            if random.random() < cure_rate or self._infect_time > 30:
                if random.random() < dead_rate:  # 死亡
                    self._status = 4
                else:  # 治愈
                    self._status = 0
                    self._virus = 0
                    self._antibody_level = random.uniform(0.95, 1.0)  # 抗体水平设置
                return self._status

        # 病毒变异
        if self._infect_time >= 14 and self._infect_time % 7 == 0:
            self._virus = max(0.5, min(0.9, random.uniform(self._virus - 0.1, self._virus + 0.1)))

        return self._status

    def testInfected(self, virus=0.7, anti=0.):
        self._status = 1
        self._antibody_level = min(1., max(0., anti))
        self._virus = virus
